#include "storage/page/page_guard.h"
#include "buffer/buffer_pool_manager.h"
#include "common/logger.h"

namespace bustub {

BasicPageGuard::BasicPageGuard(BasicPageGuard &&that) noexcept {
  // LOG_DEBUG("that page_id=%d, is_dirty=%d, pin_count=%d", that.page_->GetPageId(), that.is_dirty_,
  // that.page_->GetPinCount());
  bpm_ = that.bpm_;
  page_ = that.page_;
  is_dirty_ = that.is_dirty_;
  is_droped_ = that.is_droped_;
  that.bpm_ = nullptr;
  that.page_ = nullptr;
  that.is_dirty_ = false;
  that.is_droped_ = false;
}

void BasicPageGuard::Drop() {
  // LOG_DEBUG("Drop");
  if (is_droped_) {
    // LOG_DEBUG("is_droped_");
    return;
  }
  is_droped_ = true;
  if ((bpm_ != nullptr) && (page_ != nullptr)) {
    // LOG_DEBUG("page_id=%d, is_dirty=%d, pin_count=%d", page_->GetPageId(), is_dirty_, page_->GetPinCount());
    bpm_->UnpinPage(page_->GetPageId(), is_dirty_);
  }
}

void BasicPageGuard::Swap(BasicPageGuard &that) noexcept {
  std::swap(bpm_, that.bpm_);
  std::swap(page_, that.page_);
  std::swap(is_dirty_, that.is_dirty_);
  std::swap(is_droped_, that.is_droped_);
}

auto BasicPageGuard::operator=(BasicPageGuard &&that) noexcept -> BasicPageGuard & {
  // LOG_DEBUG("operator=");
  if (this != &that) {
    Drop();
    bpm_ = that.bpm_;
    page_ = that.page_;
    is_dirty_ = that.is_dirty_;
    is_droped_ = that.is_droped_;
    that.bpm_ = nullptr;
    that.page_ = nullptr;
    that.is_dirty_ = false;
    that.is_droped_ = false;
  }
  // BasicPageGuard(std::move(that)).Swap(*this);
  return *this;
}

BasicPageGuard::~BasicPageGuard() {
  // LOG_DEBUG("~BasicPageGuard;");
  Drop();
};  // NOLINT

ReadPageGuard::ReadPageGuard(ReadPageGuard &&that) noexcept : guard_(std::move(that.guard_)) {
  // LOG_DEBUG("ReadPageGuard");
}

auto ReadPageGuard::operator=(ReadPageGuard &&that) noexcept -> ReadPageGuard & {
  // LOG_DEBUG("operator=");
  if (this != &that) {
    Drop();
    guard_ = std::move(that.guard_);
  }
  return *this;
}

void ReadPageGuard::Drop() {
  // LOG_DEBUG("Drop");
  if (guard_.is_droped_) {
    // LOG_DEBUG("is_droped_");
    return;
  }
  guard_.Drop();
  if ((guard_.bpm_ != nullptr) && (guard_.page_ != nullptr)) {
    guard_.page_->RUnlatch();
  }
}

ReadPageGuard::~ReadPageGuard() {
  // LOG_DEBUG("~ReadPageGuard");
  Drop();
}  // NOLINT

WritePageGuard::WritePageGuard(WritePageGuard &&that) noexcept : guard_(std::move(that.guard_)) {
  // LOG_DEBUG("WritePageGuard");
}

auto WritePageGuard::operator=(WritePageGuard &&that) noexcept -> WritePageGuard & {
  // LOG_DEBUG("operator=");
  if (this != &that) {
    Drop();
    guard_ = std::move(that.guard_);
  }
  return *this;
}

void WritePageGuard::Drop() {
  // LOG_DEBUG("Drop");
  if (guard_.is_droped_) {
    // LOG_DEBUG("is_droped_");
    return;
  }
  guard_.Drop();
  if ((guard_.bpm_ != nullptr) && (guard_.page_ != nullptr)) {
    guard_.page_->WUnlatch();
  }
}

WritePageGuard::~WritePageGuard() {
  // LOG_DEBUG("~WritePageGuard");
  Drop();
}  // NOLINT

}  // namespace bustub
